package com.shanzmoo.base.controller;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.handler.inter.IExcelExportServer;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.shanzmoo.base.bean.ExeclField;
import com.shanzmoo.base.bean.PageReqBase;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Supplier;

import static org.springframework.http.HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS;
import static org.springframework.http.HttpHeaders.CONTENT_DISPOSITION;

/**
 * controller父类
 *
 * @author fs
 */
@Slf4j
public abstract class BaseController {

    @Autowired
    protected HttpServletRequest request;

    @Autowired
    protected HttpServletResponse response;

    public static final long EXPORT_MAX_NUM = 100000;
    /**
     * 向客户端写出表格数据
     *
     * @param workbook 表格数据
     * @param fileName 文件名称（eq: text.xls）
     * @throws IOException
     */
    protected void writeWorkbook(@NonNull Workbook workbook, @NonNull String fileName) throws IOException {
        try {
            response.setContentType("application/octet-stream; charset=utf-8");
            response.setHeader(CONTENT_DISPOSITION, "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
            response.setHeader("fileName", URLEncoder.encode(fileName, "UTF-8"));
            response.setHeader(ACCESS_CONTROL_EXPOSE_HEADERS, "Content-Disposition, fileName");
            workbook.write(response.getOutputStream());
        } finally {
            try {
                workbook.close();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    /**
     * 向客户端写出表格数据
     *
     * @param pojoClass 类clazz
     * @param dataSet   数据
     * @param fileName  文件名称（例: text.xls）
     * @throws IOException
     */
    protected void writeWorkbook(@NonNull Class<?> pojoClass, @NonNull Collection<?> dataSet, @NonNull String fileName) throws IOException {
        writeWorkbook(getWorkbook(pojoClass, dataSet, null), fileName);
    }

    /**
     * 向客户端写出表格数据
     *
     * @param pojoClass 类clazz
     * @param dataSet   数据
     * @param title     标题
     * @param fileName  文件名称（例: text.xls）
     * @throws IOException
     */
    protected void writeWorkbook(@NonNull Class<?> pojoClass, @NonNull Collection<?> dataSet, @NonNull String title, @NonNull String fileName) throws IOException {
        writeWorkbook(getWorkbook(pojoClass, dataSet, title), fileName);
    }

    /**
     * 大数据导出
     *
     * @param pojoClass   类clazz
     * @param server      查询数据的接口
     * @param queryParams 查询数据的参数
     * @param fileName    文件名称（例: text.xls）
     * @throws IOException
     */
    protected void writeWorkbook(@NonNull Class<?> pojoClass, IExcelExportServer server, Object queryParams, @NonNull String fileName) throws IOException {
        final ExportParams params = new ExportParams();
        final Workbook workbook = ExcelExportUtil.exportBigExcel(params, pojoClass, server, queryParams);
        writeWorkbook(workbook, fileName);
    }

    /**
     * 大数据导出
     *
     * @param pojoClass   类clazz
     * @param supplier    supplier
     * @param fileName    文件名称（例: text.xls）
     * @param queryParams 查询参数
     * @throws IOException
     */
    protected void writeWorkbook(final @NonNull Class<?> pojoClass, final @NonNull String fileName, @NonNull final Supplier<IPage> supplier, @NonNull final PageReqBase queryParams) throws IOException {
        final ExportParams params = new ExportParams();
        if (queryParams.getExportMaxLimit() == -1) {
            queryParams.setExportMaxLimit(5000L);
        }
        final Workbook workbook = ExcelExportUtil.exportBigExcel(params, pojoClass, (obj, page) -> {
            final PageReqBase form = (PageReqBase) obj;
            form.setPageNum(Convert.toLong(page));
            final IPage records = supplier.get();
            if (records == null || CollUtil.isEmpty(records.getRecords())) {
                return null;
            }
            return records.getRecords();
        }, queryParams);
        writeWorkbook(workbook, fileName);
    }

    /**
     * 大数据导出
     *
     * @param fieldMap   字段map
     * @param supplier    supplier
     * @param fileName    文件名称（例: text.xls）
     * @param queryParams 查询参数
     * @throws IOException
     */
    protected void writeWorkbook(final @NonNull ExeclField fieldMap, final @NonNull String fileName, @NonNull final Supplier<IPage> supplier, @NonNull final PageReqBase queryParams) throws IOException {
        final ExportParams params = new ExportParams();
        if (queryParams.getExportMaxLimit() == -1) {
            queryParams.setExportMaxLimit(5000L);
        }
        List<ExcelExportEntity> list = new ArrayList();
        Set<String> keys = fieldMap.keySet();
        for(String key:keys){
            ExcelExportEntity entity = new ExcelExportEntity(fieldMap.get(key),key);
            entity.setWidth(20);
            list.add(entity);
        }
        final Workbook workbook = ExcelExportUtil.exportBigExcel(params, list, (obj, page) -> {
            final PageReqBase form = (PageReqBase) obj;
            form.setPageNum(Convert.toLong(page));
            final IPage records = supplier.get();
            if (records == null || CollUtil.isEmpty(records.getRecords())) {
                return null;
            }
            if(page==1){
                //对数据进行格式化
                Object data = records.getRecords().get(0);
                if (data != null){
                    for(ExcelExportEntity eee:list){
                        Class clazz = ReflectUtil.getField(data.getClass(),eee.getKey().toString()).getType();
                        if(ClassUtil.isAssignable(LocalDate.class,clazz)){
                            eee.setFormat("yyyy-MM-dd");
                        }else if(ClassUtil.isAssignable(Date.class,clazz) || ClassUtil.isAssignable(LocalDateTime.class,clazz)){
                            eee.setFormat("yyyy-MM-dd HH:mm:ss");
                        }else if(clazz.isEnum()){
                            eee.setEnumExportField("desc");
                        }
                    }
                }
            }
            return records.getRecords();
        }, queryParams);
        writeWorkbook(workbook, fileName);
    }
    /**
     * 大数据导出
     *
     * @param pojoClass     类clazz
     * @param supplier      supplier
     * @param fileName      文件名称（例: text.xls）
     * @param queryParams   查询参数
     * @param countSupplier 总数
     * @throws IOException
     */
    protected void writeWorkbook(final @NonNull Class<?> pojoClass, final @NonNull String fileName, @NonNull final Supplier<IPage> supplier, @NonNull final PageReqBase queryParams, final Supplier<Long> countSupplier) throws IOException {
        if (countSupplier != null) {
            Long count = countSupplier.get();
            if (count != null && count.longValue() > EXPORT_MAX_NUM) {
                throw new RuntimeException(String.format("数据过多请筛选后导出，当前总数%d条，限制最大条数%d条", count, EXPORT_MAX_NUM));
            }
        }
        writeWorkbook(pojoClass, fileName, supplier, queryParams);
    }

    /**
     * 导入数据
     *
     * @param inputStream 文件流
     * @param pojoClass   类型
     * @param <T>         返回类型
     * @return 结果集
     * @throws Exception 异常信息
     */
    protected <T> List<T> importExcel(@NonNull InputStream inputStream, @NonNull Class<?> pojoClass) throws Exception {
        // 读取excel
        final ImportParams params = new ImportParams();
        params.setHeadRows(1);
        params.setNeedVerify(true);
        return ExcelImportUtil.importExcel(inputStream, pojoClass, params);
    }

    /**
     * 获取表格
     *
     * @param pojoClass 类型
     * @param dataSet   数据
     * @return
     */
    protected Workbook getWorkbook(Class<?> pojoClass, Collection<?> dataSet, String title) {
        final ExportParams exportParams = new ExportParams();
        exportParams.setType(ExcelType.HSSF);
        if (title != null) {
            exportParams.setTitle(title);
        }
        return ExcelExportUtil.exportExcel(exportParams, pojoClass, dataSet);
    }

    protected Workbook getWorkbook(Class<?> pojoClass, Collection<?> dataSet) {
        return getWorkbook(pojoClass, dataSet, null);
    }
}
